package com.ruoyi.common.utils.jm.ofd;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import static com.ruoyi.common.utils.Base64Utils.ESSGetBase64Encode;
import static com.ruoyi.common.utils.file.FileUtils.File2byte;
import static com.ruoyi.common.utils.file.FileUtils.byte2File;

public class OFDServerSign {

	//从电子发票的 Doc_0\Pages\Page_0\Content.xml 中获取 docinfo
	public static String GetTaxDocInfo(String sPageXml)
	{
		//文档名称
		String sDocName = "1002";
		//发票代码
		String sFpdm = "1085";
		//发票号码
		String sFphm = "1086";
		//合计税额
		String sHjse = "1108";
		//合计金额
		String sHjje = "1107";
		//开票日期
		String sKprq = "1087";
		//校验码
		String sJym = "1088";
		//购买人识别号
		String sGmfSbh = "1090";
		//销售方识别号
		String sXsfSbh = "1095";

        //1.创建Reader对象
        SAXReader reader = new SAXReader();
        //2.加载xml
        Document document = null;
		try {
			document = reader.read(new File(sPageXml));
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
        //3.获取根节点
        Element rootElement = document.getRootElement();
        Iterator<Element> iterator = rootElement.elementIterator();
        while (iterator.hasNext()){
            Element stu = (Element) iterator.next();
            if(!"Content".equals(stu.getName())) {
				continue;
			}
            Iterator<Element> iterator1 = stu.elementIterator();
            while (iterator1.hasNext()){
                Element stuChild = (Element) iterator1.next();
                if(!stuChild.getName().equals("Layer")) {
					continue;
				}
                Iterator<Element> iterator2 = stuChild.elementIterator();
                while (iterator2.hasNext()){
                	Element stuChild2 = (Element) iterator2.next();
                	if(!stuChild2.getName().equals("TextObject")) {
						continue;
					}
                	String sID = stuChild2.attributeValue("ID");
        			if(sID == null) {
						continue;
					}
        			if(sID.equals("")) {
						continue;
					}
                	//当前文字的位置信息
                	Iterator<Element> iterator3 = stuChild2.elementIterator();
                	while (iterator3.hasNext()){
                		Element stuChild3 = (Element) iterator3.next();
                		if(stuChild3.getName().equals("TextCode"))
                		{
							switch (sID) {
								case "1002":
									sDocName = stuChild3.getStringValue();
									break;
								case "1085":
									sFpdm = stuChild3.getStringValue();
									break;
								case "1086":
									sFphm = stuChild3.getStringValue();
									break;
								case "1108":
									sHjse = stuChild3.getStringValue();
									break;
								case "1107":
									sHjje = stuChild3.getStringValue();
									break;
								case "1087":
									sKprq = stuChild3.getStringValue();
									break;
								case "1088":
									sJym = stuChild3.getStringValue();
									break;
								case "1090":
									sGmfSbh = stuChild3.getStringValue();
									break;
								case "1095":
									sXsfSbh = stuChild3.getStringValue();
									break;
								default:
									continue;
							}
                		}
                	}
                }
            }
        }

        String sTaxDocInfo = "{\"DocId\":\"\",\"DocName\":\"AAAA\",\"Entry\":\"/Doc_0/Signs/Sign_0/Signature.xml\",\"发票代码\":\"BBBB\",\"发票号码\":\"CCCC\",\"合计税额\":\"DDDD\",\"合计金额\":\"EEEE\",\"开票日期\":\"FFFF\",\"校验码\":\"GGGG\",\"购买方纳税人识别号\":\"HHHH\",\"销售方纳税人识别号\":\"IIII\"}";
        sTaxDocInfo = sTaxDocInfo.replaceAll("AAAA", sDocName);
        sTaxDocInfo = sTaxDocInfo.replaceAll("BBBB", sFpdm);
        sTaxDocInfo = sTaxDocInfo.replaceAll("CCCC", sFphm);
        sTaxDocInfo = sTaxDocInfo.replaceAll("DDDD", sHjse);
        sTaxDocInfo = sTaxDocInfo.replaceAll("EEEE", sHjje);
        sTaxDocInfo = sTaxDocInfo.replaceAll("FFFF", sKprq);
        sTaxDocInfo = sTaxDocInfo.replaceAll("GGGG", sJym);
        sTaxDocInfo = sTaxDocInfo.replaceAll("HHHH", sGmfSbh);
        sTaxDocInfo = sTaxDocInfo.replaceAll("IIII", sXsfSbh);

        return sTaxDocInfo;
	}

	private static boolean deleteDir(File dirPath) {
	    if (!dirPath.exists()) {
	        return false;
	    }
	    if (dirPath.isFile()) {
	        return dirPath.delete();
	    } else {
	        for (File file : dirPath.listFiles()) {
	        	deleteDir(file);
	        }
	    }
	    return dirPath.delete();
	}

	//遍历文件夹下所有文件
	private static void GetFiles(File fDir, List<File> list) {
		File[] fs = fDir.listFiles();
		for(File f:fs){
			if(f.isDirectory()) {
				GetFiles(f,list);
			} else {
				list.add(f);
			}
		}
	}
	private String signatureXMLPath = "Doc_0/Signs/Sign_0/Signature.xml";


	private static byte[] SignBySealID(String sSignatureXmlPath,
									   byte[] bCert,byte[] bPub,byte[] bPrv,byte[] bSeal,
									   String sSealID,String sDocProperty,String sSignTime,int iType) throws IOException {

		byte[] bXml = File2byte(sSignatureXmlPath);

		byte[] bDocHash = GmUtil.sm3(bXml);

		String sDocPro = "";
		if(sDocProperty == null || sDocProperty.equals("")) {
			sDocPro = "Doc_0/Signs/Sign_0/Signature.xml";
		} else {
			sDocPro = sDocProperty;
		}
		String sTest ="true";
		if(sTest.equals("true")){
			byte[] bSign = null;
			if(iType == 1 || iType == 2) {
				bSign = GBSealForAgreement.SignIt(bSeal, sSignTime, bDocHash, sDocPro, bCert, "1.2.156.10197.1.501", new String(bPub), new String(bPrv));
			} else {
				bSign = AKSealForAgreement.SignIt(bSeal, sSignTime, bDocHash, sDocPro, bCert, "1.2.156.10197.1.501", new String(bPub), new String(bPrv));
			}
			return bSign;
		}else{
			//应根据印章ID查印章证书\印章数据\私钥索引
			String sCertPath = "";
			String sSealPath = "";
			int iPrvIndex = 27;
			//调用加密机签名
			byte[] bSign = null;

			if(iType == 1 || iType == 2) {
				bSign = GBSealForAgreement.JMJSign(bCert, bSeal, sSignTime, bDocHash, sDocProperty, iPrvIndex);
			} else {
				bSign = AKSealForAgreement.JMJSign(bCert, bSeal, sSignTime, bDocHash, sDocProperty, iPrvIndex);
			}
			return bSign;
		}
	}




	//获取当前页码中 关键字 的位置
	private static Vector<String> GetPositionByTextInPage(String sPageXml,String sKeyWord)
	{
		boolean blHasTmp = false;
		Vector<String> v = new Vector<String>();
		String sCurrentPos = "";
        //1.创建Reader对象
        SAXReader reader = new SAXReader();
        //2.加载xml
        Document document = null;
		try {
			document = reader.read(new File(sPageXml));
		} catch (DocumentException e) {
			e.printStackTrace();
			return null;
		}
        //3.获取根节点
        Element rootElement = document.getRootElement();
        Iterator<Element> iterator = rootElement.elementIterator();
        while (iterator.hasNext()){
            Element stu = (Element) iterator.next();
            if(stu.getName().equals("Template")) {
				blHasTmp = true;
			}
            if(stu.getName().equals("Content") == false) {
				continue;
			}
            Iterator<Element> iterator1 = stu.elementIterator();
            while (iterator1.hasNext()){
                Element stuChild = (Element) iterator1.next();
                if(stuChild.getName().equals("Layer") == false) {
					continue;
				}
                Iterator<Element> iterator2 = stuChild.elementIterator();
                while (iterator2.hasNext()){
                	Element stuChild2 = (Element) iterator2.next();
                	if(stuChild2.getName().equals("TextObject") == false) {
						continue;
					}
                	//当前文字的位置信息
                	sCurrentPos = stuChild2.attribute("Boundary").getStringValue();
                	Iterator<Element> iterator3 = stuChild2.elementIterator();
                	while (iterator3.hasNext()){
                		Element stuChild3 = (Element) iterator3.next();
                		if(stuChild3.getName().equals("TextCode"))
                		{
                			//当前文字的内容
                			if(stuChild3.getStringValue().indexOf(sKeyWord) != -1)
                			{
                				String s =sPageXml + "," + sCurrentPos + "," + stuChild3.getStringValue();
                				v.add(s);
                			}
                		}
                	}
                }
            }
        }

        if(blHasTmp)
        {
        	String sZipPath = "";
        	int iB = sPageXml.indexOf("/Doc_0/");
        	if(iB == -1) {
				iB = sPageXml.indexOf("\\Doc_0\\");
			}
        	sZipPath = sPageXml.substring(0,iB);

        	//检查模板
        	iterator = rootElement.elementIterator();
        	while (iterator.hasNext()){
                Element stu = (Element) iterator.next();
                if(stu.getName().equals("Template")){
                	String sTplId = stu.attributeValue("TemplateID");
                	//从 Doc_0\Document.xml 中获取对应ID的模板ｘｍｌ的路径
                	String sTplPath = GetTplPath(sZipPath,sTplId);
                	if(sTplPath == null) {
						return null;
					}
                	//在模板文件中查找关键字并记录到Vector中
                    //1.创建Reader对象
                    SAXReader readerTpl = new SAXReader();
                    //2.加载xml
                    Document documentTpl = null;
            		try {
            			documentTpl = readerTpl.read(new File(sTplPath));
            		} catch (DocumentException e) {
            			// TODO Auto-generated catch block
            			e.printStackTrace();
            			return null;
            		}

                    //3.获取根节点
                    Element rootElementTpl = documentTpl.getRootElement();
                    Iterator<Element> iteratorTpl = rootElementTpl.elementIterator();
                    while (iteratorTpl.hasNext()){
                        Element stuTpl = (Element) iteratorTpl.next();
                        if(stuTpl.getName().equals("Content") == false) {
							continue;
						}

                        Iterator<Element> iterator1Tpl = stuTpl.elementIterator();
                        while (iterator1Tpl.hasNext()){
                            Element stuChildTpl = (Element) iterator1Tpl.next();
                            if(stuChildTpl.getName().equals("Layer") == false) {
								continue;
							}
                            Iterator<Element> iterator2Tpl = stuChildTpl.elementIterator();
                            while (iterator2Tpl.hasNext()){
                            	Element stuChild2Tpl = (Element) iterator2Tpl.next();
                            	if(stuChild2Tpl.getName().equals("TextObject") == false) {
									continue;
								}
                            	//当前文字的位置信息
                            	sCurrentPos = stuChild2Tpl.attribute("Boundary").getStringValue();
                            	Iterator<Element> iterator3Tpl = stuChild2Tpl.elementIterator();
                            	while (iterator3Tpl.hasNext()){
                            		Element stuChild3Tpl = (Element) iterator3Tpl.next();
                            		if(stuChild3Tpl.getName().equals("TextCode"))
                            		{
                            			//当前文字的内容
                            			if(stuChild3Tpl.getStringValue().indexOf(sKeyWord) != -1)
                            			{
                            				String s = sPageXml + "," + sCurrentPos + "," + stuChild3Tpl.getStringValue();
                            				if(v.contains(s) == false)
                            				{
                            					v.add(s);
                            				}
                            			}
                            		}
                            	}
                            }
                        }
                    }
                }
        	}
        }

        if(blHasTmp)
        {
        	//存在模板，需要重新排序
        	v = OrderVecotrY(v);
        }

        return v;
	}


	private static Vector<String> OrderVecotrY(Vector<String> v)
	{
        HashMap<Double, String> hashMap = new HashMap<>();
        double num =0.0001;
        for (String vData : v) {
            String[] splitVD = vData.split(",");
            String[] splitNum = splitVD[1].split(" ");

            Double dT = Double.parseDouble(splitNum[1]);
            dT = dT + num;

            hashMap.put(dT,vData);
            num+=0.0001;
        }
        ArrayList<Double> orderLsit = new ArrayList<>();
        Set<Double> orderNums = hashMap.keySet();
        for (Double orderNum : orderNums) {
            orderLsit.add(orderNum);
        }

        Collections.sort(orderLsit);

        Vector<String> vTmp = new Vector<String>();
        Vector<String> vRet = new Vector<String>();
//        重新赋值
        Double dbLast = 0.0;
        for (Double orderNum : orderLsit) {
        	if(vTmp.size() == 0) {
				vTmp.add(hashMap.get(orderNum));
			} else
        	{
        		if(Math.floor(orderNum) != Math.floor(dbLast))
        		{
        			//对Y相同的数据按X排序
        			Vector<String> vMid = OrderVecotrX(vTmp);
        			//存入最终vector
        			for(int k=0;k<vMid.size();k++) {
						vRet.add(vMid.elementAt(k));
					}
        			vTmp.removeAllElements();
        		}
        		vTmp.add(hashMap.get(orderNum));
        	}
        	dbLast = orderNum;
        }

        if(vTmp.size() > 0)
        {
	        Vector<String> vMid = OrderVecotrX(vTmp);
			for(int k=0;k<vMid.size();k++)
			{
				vRet.add(vMid.elementAt(k));
			}
        }
        return vRet;
	}


	private static Vector<String> OrderVecotrX(Vector<String> v)
	{
        HashMap<Double, String> hashMap = new HashMap<>();
        double num =0.0001;
        for (String vData : v) {
            String[] splitVD = vData.split(",");
            String[] splitNum = splitVD[1].split(" ");
            Double dT = Double.parseDouble(splitNum[0]);
            dT = dT + num;
            hashMap.put(dT,vData);
            num+=0.0001;
        }
        ArrayList<Double> orderLsit = new ArrayList<>();
        Set<Double> orderNums = hashMap.keySet();
        for (Double orderNum : orderNums) {
            orderLsit.add(orderNum);
        }

        Collections.sort(orderLsit);

        Vector<String> vRet = new Vector<String>();
//        重新赋值
        for (Double orderNum : orderLsit) {
        	vRet.add(hashMap.get(orderNum));
        }
        return vRet;
	}

	//根据模板文件ID 获取 模板文件路径
	private static String GetTplPath(String zipPath,String sID)
	{
		String sXml = zipPath + "/Doc_0/Document.xml";
        //1.创建Reader对象
        SAXReader reader = new SAXReader();
        //2.加载xml
        Document document = null;
		try {
			document = reader.read(new File(sXml));
		} catch (DocumentException e) {
			e.printStackTrace();
			return null;
		}
        //3.获取根节点
        Element rootElement = document.getRootElement();
        Iterator<Element> iterator = rootElement.elementIterator();
        while (iterator.hasNext()){
            Element stu = (Element) iterator.next();
            if(stu.getName().equals("CommonData") == false) {
				continue;
			}
            Iterator<Element> iterator1 = stu.elementIterator();
            while (iterator1.hasNext()){
                Element stuChild = (Element) iterator1.next();
                if(stuChild.getName().equals("TemplatePage") == false) {
					continue;
				}
                if(stuChild.attributeValue("ID").equals(sID)) {
					return zipPath + "/Doc_0/" +  stuChild.attributeValue("BaseLoc");
				}
            }
        }
        return null;
	}


	/**
	 * @author HONOR
	 * @param 	iPage,所在页码（0开始,-1用于配合关键字）
	 * @param 	iIndex，关键字出现第几次（1开始,0表示最后一个）
	 * @param 	sKeyWord	关键字
	 * @param	zipPath		OFD解压后的路径
	 * @return
	 */
	private static String GetPositionByTextInOFD(int iPage,int iIndex,String sKeyWord,String zipPath)
	{
		File f = null;
		String sPageFile = "";
		Vector<String> vPage = new Vector<String>();
		if(iPage >= 0)
		{
			sPageFile = GetPagePath(zipPath,iPage);
			if(sPageFile == null) {
				return null;
			}
			sPageFile = zipPath + "/Doc_0/" + sPageFile;

			f = new File(sPageFile);
			if(f.exists()) {
				vPage.add(sPageFile);
			} else {
				return null;
			}
		}else
		{
			//当传入的页码小于0时，将所有页码放入Vector中
			int iTmp = 0;
			while(true)
			{
				sPageFile = zipPath + "/Doc_0/Pages/Page_" + Integer.toString(iTmp) + "/Content.xml";
				f = new File(sPageFile);
				if(f.exists()) {
					vPage.add(sPageFile);
					iTmp++;
				} else {
					break;
				}
			}
		}
		if(vPage.size() == 0) {
			return null;
		}
		//至此所有可能存在关键字的页都放入了Vecotr中
		//接下来从每一页中获取关键字位置

		Vector<String> vAllContent = new Vector<String>();
		for(int i=0;i<vPage.size();i++)
		{
			sPageFile = vPage.elementAt(i);
			Vector<String> v = GetPositionByTextInPage(sPageFile,sKeyWord);
			if(v == null) {
				continue;
			}
			for(int j=0;j<v.size();j++)
			{
				String s1 = v.elementAt(j);
				vAllContent.add(s1);
			}
			v.removeAllElements();
		}
		vPage.removeAllElements();
		//到了这里，所有含有KeyWord的文字以及位置信息都放在了Vector里

		if(vAllContent.size() == 0) {
			return null;
		}

		String sPosInfo = "";
		if(iIndex > 0) {
			//指定了出现次数
			sPosInfo = vAllContent.elementAt(iIndex-1);
		}else {
			sPosInfo = vAllContent.lastElement();
		}
		return sPosInfo;
	}

	//OFD 中，并非  "Pages"文件夹中的Page_0就是第一页，Page_1就是第二页
	//显示时候的页码，是 Document.xml 中的 <ofd:pages> 中的顺序决定的
	private static String GetSealPosition(int iPage,String zipPath,String sKeyWord,int iKeyWordIndex,float iPosX,float iPosY,int iWidth,int iHeight) {
		String sPage = "";
		//如果传入了页码信息，则根据页码信息获取对应的页面的ID
		if(iPage >= 0)
		{
			sPage = GetPageID(zipPath,iPage);
			if(sPage == null) {
				return null;
			}
		}else
		{
			//如果没有传入页码信息，则必定是按关键字
			if(sKeyWord == null || sKeyWord.equals("")){
				System.out.println("GetSealPosition:	Param Error");
				return null;
			}
		}
		if(sKeyWord == null || sKeyWord.equals(""))
		{
			//按页码和绝对坐标定位
			String s0 = sPage;
			String s1 = Float.toString(iPosX);
			String s2 = Float.toString(iPosY);
			String s3 = Float.toString(iWidth) ;
			String s4 = Float.toString(iHeight);
			return s0 + " " + s1 + " " + s2 + " " + s3 + " " + s4;
		}else
		{
			//找到对应的KeyWord位置
			String sPosInfo = GetPositionByTextInOFD(iPage,iKeyWordIndex,sKeyWord,zipPath);
			if( sPosInfo == null )
			{
				System.out.println("GetSealPosition:	Get Position By Keyword Error");
				return null;
			}
			//返回的是
			//D:/tmp/test/Doc_0/Pages/Page_4/Content.xml,147 278.7 16.83 3.17,开票日期：
			String s0 = "";
			String[] ss = sPosInfo.split(",");
			int iB = sPosInfo.indexOf("Page_");
			int iE = sPosInfo.indexOf("/", iB);
			if(iE == -1) {
				iE = sPosInfo.indexOf("\\", iB);
			}
			s0 = sPosInfo.substring(iB + 5,iE);
			if(iPage >= 0){
				s0 = Integer.toString(iPage);
			}
			sPosInfo = ss[1];
//			int[] iKeyWordPos = new int[3];
//			int iX = iKeyWordPos[0] + iPosX;
//			int iY = iKeyWordPos[1] + iPosY;
			s0 = GetPageID(zipPath,Integer.parseInt(s0));
			ss = sPosInfo.split(" ");
			Double dX = Double.parseDouble(ss[0]);
			Double dY = Double.parseDouble(ss[1]);
			if(sKeyWord != null && sKeyWord.length() > 0)
			{
				dX = dX + iPosX;
				dY = dY + iPosY;
			}

			String s1 = Double.toString(dX) + ".0";
			String s2 = Double.toString(dY) + ".0";
			String s3 = Integer.toString(iWidth);
			String s4 = Integer.toString(iHeight);
			return s0 + " " + s1 + " " + s2 + " " + s3 + " " + s4;
		}
	}

	//根据用户指定的页码来获得Page的路径
	private static String GetPagePath(String sZipDir,int iPage){
		String sPageXml = sZipDir + "/Doc_0/Document.xml";
		//1.创建Reader对象
        SAXReader reader = new SAXReader();
        //2.加载xml
        Document document;
		try {
			document = reader.read(new File(sPageXml));
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
        //3.获取根节点
        Element rootElement = document.getRootElement();
        Iterator<Element> iterator = rootElement.elementIterator();
        while (iterator.hasNext()){
            Element stu = (Element) iterator.next();
            if(stu.getName().equals("Pages") == true){
            	Iterator<Element> iterator1 = stu.elementIterator();
            	int iCount = 0;
            	while (iterator1.hasNext()){
            		Element stu1 = (Element) iterator1.next();
            		String s = stu1.attributeValue("BaseLoc");
            		if(iCount == iPage) {
						return s;
					} else {
						iCount++;
					}
            	}
            	break;
            }
        }
        return null;
	}

	//根据用户指定的页码来获得PageID
	private static String GetPageID(String sZipDir,int iPage)
	{
		String sPageXml = sZipDir + "/Doc_0/Document.xml";
		//1.创建Reader对象
        SAXReader reader = new SAXReader();
        //2.加载xml
        Document document;
		try {
			document = reader.read(new File(sPageXml));
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
        //3.获取根节点
        Element rootElement = document.getRootElement();
        Iterator<Element> iterator = rootElement.elementIterator();
        while (iterator.hasNext()){
            Element stu = (Element) iterator.next();
            if(stu.getName().equals("Pages") == true){
            	Iterator<Element> iterator1 = stu.elementIterator();
            	int iCount = 0;
            	while (iterator1.hasNext()){
            		Element stu1 = (Element) iterator1.next();
            		String s = stu1.attributeValue("ID");
            		if(iCount == iPage) {
						return s;
					} else {
						iCount++;
					}
            	}
            	break;
            }
        }
        return null;
	}

	//对税务发票签章
//	public static byte[] SignTaxReceipt(byte[] bOfdFile,String sSealID,String sSignTime) throws Exception {
//		return SignOFD(bOfdFile,sSealID,sSignTime,"",0,null,0,90,8,30,20,1);
//	}

	/*
	 *	bOfdFile		被签章的OFD
	 * 	sSealID			需要使用的印章ID
	 *	sSignTime		签章时间
	 *	sDocProperty	OFD文档的DOCINFO
	 *	iPage			印章所在页码（从 0 开始，传入负数时，认为是关键字签章
	 *	sKeyWord		定位关键字（从 1 开始，0 表示最后一个）
	 *	iPosX iPosY		当页码定位时，此参数是绝对坐标；当关键字定位时，此参数是偏移量
	 *	iWidth iHeight	印章显示宽、高
	 *	iType			1：电子发票 2:一般GB 3：一般AK
	 */
	public static byte[] SignOFD(byte[] bOfdFile,String sSealID,String sSignTime,String sDocProperty
								 ,byte[]bCert,byte[] bPub,byte[] bPrv,byte[] bSeal,int iPage,
								 String sKeyWord,int iKeywordIndex,float iPosX,float iPosY,int iWidth,int iHeight,int iType) throws Exception {

		//临时文件夹名
		String sFileName = UUID.randomUUID().toString().replaceAll("-","");
		String sFilePath;
		//解压缩后的文件夹路径
		String sZipDir;
		String sTmpFilePath;
		String sTmpFileContent;
		File f = null;
		FileOutputStream fos = null;
		byte[] bFile = null;
		//印章索引
		int iSealIndex = -1;
		int iB = 0;
		int iE = 0;

		//将传入的OFD写成临时文件
		f = File.createTempFile(sFileName, ".zip");
		//临时文件完整路径
		sFilePath = f.getAbsolutePath();
		//无后缀名的完整路径
		sZipDir = sFilePath.substring(0, sFilePath.length() - 4);
		//将OFD文件输出为后缀为zip的文件
		byte2File(bOfdFile,sFilePath);
		//解压缩OFD文件（OFD文件本身是一个zip格式的压缩包）
		ZipUtil.zipUncompress(sFilePath, sZipDir);

		//根据传入的参数获得本次签章的位置信息，返回值是 “页码 X1 Y1 X2 Y2”
		String sSealPosition = GetSealPosition(iPage,sZipDir,sKeyWord,iKeywordIndex,iPosX,iPosY,iWidth,iHeight);
		String[] sTmp = sSealPosition.split(" ");
		if(sTmp.length != 5) {
			return null;
		}
		String sPage = sTmp[0];
		sSealPosition = sTmp[1] + " " + sTmp[2] + " " + sTmp[3] + " " + sTmp[4];

		//获取当前UTC时间
		String sSignTimeZ = getUTCTimeStr();

		//将OFD.xml文件中的内容读入到内存中。
		sTmpFilePath = sZipDir + "/OFD.xml";
		bFile = File2byte(new File(sTmpFilePath));
		//若以前签过章，这个文档中会有<ofd:Signatures>标签
		//并且/Doc_0/Signs/Signatures.xml这个文件中有下一次签署时候的印章索引号
		sTmpFileContent = new String(bFile);
		if(!sTmpFileContent.contains("<ofd:Signatures>")) {
			iSealIndex = 1;			//若没有签章，则印章索引从1开始
		} else {
			//已经存在签章，则读取<ofd:MaxSignId>的值
			sTmpFilePath =  sZipDir + "/Doc_0/Signs/Signatures.xml";
			bFile = File2byte(new File(sTmpFilePath));
			sTmpFileContent = new String(bFile);
			iB = sTmpFileContent.indexOf("<ofd:MaxSignId>");
			iE = sTmpFileContent.indexOf("</ofd:MaxSignId>");
			if(iB == -1 || iE == -1) {
				return null;
			}
			sTmpFileContent = sTmpFileContent.substring(iB + 15, iE);
			iSealIndex = Integer.parseInt(sTmpFileContent);
			iSealIndex ++;
		}

		String sContent;

		sContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
		sContent = sContent + "<ofd:Signature xmlns:ofd=\"http://www.ofdspec.org/2016\">";
		sContent = sContent + "<ofd:SignedInfo><ofd:Provider ProviderName=\"BJCLT_TAX\" Company=\"BJCLT\" Version=\"4.0\"/>";
		sContent = sContent + "<ofd:SignatureMethod>1.2.156.10197.1.501</ofd:SignatureMethod><ofd:SignatureDateTime>" + sSignTimeZ + "</ofd:SignatureDateTime>";
		sContent = sContent + "<ofd:References CheckMethod=\"1.2.156.10197.1.401\">";

		//列举出OFD文件中包含的所有文件的名称
		List<File> files = new ArrayList<>();
		GetFiles(new File(sZipDir),files);
		//计算除了 Signatures.xml 之外的其他文件的HASH值
		for (File fileLoop:files) {
			if (fileLoop.getName().contains("Signatures.xml")){
				continue;
			}
			byte[] bHash = File2byte(fileLoop);
			//计算hash
			bHash = GmUtil.sm3(bHash);
			String sHash = ESSGetBase64Encode(bHash);

			String stmp = fileLoop.getPath().replace("\\", "/");
			int k = stmp.indexOf("/Doc_0/");
			if(k == -1) {
				continue;
			}
			String sk = stmp.substring(k);
			String st = "<ofd:Reference FileRef=\"" + sk + "\"><ofd:CheckValue>";
			st = st + sHash + "</ofd:CheckValue></ofd:Reference>";
			sContent = sContent + st;
		}
		sContent = sContent + "</ofd:References><ofd:StampAnnot PageRef=\"" + sPage + "\" ID=\"" + iSealIndex + "\" Boundary=\""
				+ sSealPosition + "\"/></ofd:SignedInfo><ofd:SignedValue>/Doc_0/Signs/Sign_" + (iSealIndex-1) +
				"/SignedValue.dat</ofd:SignedValue></ofd:Signature>";

		File fSignDir1 = new File(sZipDir + "/Doc_0/Signs/");
		if(!fSignDir1.exists()) {
			fSignDir1.mkdir();
		}
		File fSignDir2 = new File(sZipDir + "/Doc_0/Signs/Sign_" + Integer.toString(iSealIndex-1));
		if(!fSignDir2.exists()) {
			fSignDir2.mkdir();
		}

		if( iSealIndex == 1 )
		{
			f = new File(sZipDir + "/OFD.xml");
			byte[] bOfdXml = File2byte(f);
			String sOfdXml1 = new String(bOfdXml);
			int itmp = sOfdXml1.indexOf("<ofd:DocRoot>Doc_0/Document.xml</ofd:DocRoot>");
			String s1 = sOfdXml1.substring(0, itmp);
			s1 = s1 + "<ofd:DocRoot>Doc_0/Document.xml</ofd:DocRoot>\n";
			s1 = s1 + "<ofd:Signatures>/Doc_0/Signs/Signatures.xml</ofd:Signatures>";
			itmp = itmp + "<ofd:DocRoot>Doc_0/Document.xml</ofd:DocRoot>".length();
			String s2 = sOfdXml1.substring(itmp);
			s1 = s1 + s2;
			byte2File(s1.getBytes(),sZipDir + "/OFD.xml");
			String sSignatures = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
			sSignatures = "<ofd:Signatures xmlns:ofd=\"http://www.ofdspec.org/2016\"><ofd:MaxSignId>1</ofd:MaxSignId><ofd:Signature ID=\"1\" " +
					"BaseLoc=\"Sign_0/Signature.xml\"/></ofd:Signatures>";

			byte2File(sSignatures.getBytes(),sZipDir + "/Doc_0/Signs/Signatures.xml");
		}else {
			sTmpFilePath =  sZipDir + "/Doc_0/Signs/Signatures.xml";
			bFile = File2byte(sTmpFilePath);
			sTmpFileContent = new String(bFile);
			String sSignatures = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
			sSignatures = sSignatures + "<ofd:Signatures xmlns:ofd=\"http://www.ofdspec.org/2016\">";
			sSignatures = sSignatures + "<ofd:MaxSignId>" + (iSealIndex) + "</ofd:MaxSignId>";
			sSignatures = sSignatures + "<ofd:Signature BaseLoc=\"Sign_" + (iSealIndex-1) + "/Signature.xml\" Type=\"Seal\" ID=\"" +
					Integer.toString(iSealIndex) + "\"/>\n";
			for(int i=0;i<iSealIndex;i++)
			{
				String s = "Sign_" + i + "/Signature.xml";
				if(sTmpFileContent.indexOf(s) != -1) {
					sSignatures = sSignatures + "<ofd:Signature BaseLoc=\"Sign_" + (i) + "/Signature.xml\" Type=\"Seal\" ID=\"" + (i+1) + "\"/>";
				}
			}

			sSignatures += "</ofd:Signatures>";

			byte2File(sSignatures.getBytes(),sTmpFilePath);
		}

		byte2File(sContent.getBytes(),sZipDir + "/Doc_0/Signs/Sign_" + (iSealIndex-1) + "/Signature.xml");

		byte[] bSignVal = null;
		if(iType == 1)
		{
			String sTaxDocInfo = GetTaxDocInfo(sZipDir + "/Doc_0/Pages/Page_0/Content.xml");
			bSignVal = SignBySealID(sZipDir + "/Doc_0/Signs/Sign_" + (iSealIndex-1) + "/Signature.xml",
					bCert,bPub,bPrv,bSeal,
					sSealID, sTaxDocInfo, sSignTimeZ,1);
		}else if(iType == 2)
		{
			bSignVal = SignBySealID(sZipDir + "/Doc_0/Signs/Sign_" + (iSealIndex-1) + "/Signature.xml",
					bCert,bPub,bPrv,bSeal,
					sSealID, "Doc_0/Signs/Sign_" + (iSealIndex-1) + "/Signature.xml", sSignTimeZ,2);
		}else {
			bSignVal = SignBySealID(sZipDir + "/Doc_0/Signs/Sign_" + (iSealIndex-1) + "/Signature.xml",
					bCert,bPub,bPrv,bSeal,
					sSealID, "Doc_0/Signs/Sign_" + (iSealIndex-1) + "/Signature.xml", sSignTimeZ,3);
		}
		byte2File(bSignVal,sZipDir + "/Doc_0/Signs/Sign_" +  (iSealIndex-1) + "/SignedValue.dat");

		ByteArrayOutputStream out = new ByteArrayOutputStream();

		ZipUtil.toZip(sZipDir + "/Doc_0", out, true);
		deleteDir(new File(sZipDir));
		deleteDir(new File(sFilePath));
		byte[] bRet = out.toByteArray();
		out.close();
		return bRet;
	}


   public static String getUTCTimeStr() {
        StringBuffer UTCTimeBuffer = new StringBuffer();
        Calendar cal = Calendar.getInstance() ;
        //时区偏移量
        int zoneOffset = cal.get(Calendar.ZONE_OFFSET);
        //夏令时偏移量
        int dstOffset = cal.get(Calendar.DST_OFFSET);
        cal.add(Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH)+1;
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int minute = cal.get(Calendar.MINUTE);
        UTCTimeBuffer.append(year).append("-").append(month).append("-").append(day) ;
        UTCTimeBuffer.append(" ").append(hour).append(":").append(minute) ;
        try{
        	DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm") ;
            Date now = format.parse(UTCTimeBuffer.toString()) ;
       // 	now = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            return sdf.format(now) + "Z";
        }catch(ParseException e)
        {
            e.printStackTrace() ;
        }

	   return null ;
    }
}
